using System;
using System.Net;
using System.Reflection;
using System.Xml.Linq;
using log4net;

namespace AgileDashboard.AppCode
{
    /// <summary>
    /// Responsible for fetching data from Version One instance
    /// </summary>
    public class RestDataConnection : IDataConnection
    {

        private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        /// <summary>
        /// Fetches REST data from Version One instance based on a query
        /// </summary>
        /// <param name="query">the query portion of a Version One REST API request</param>
        /// <returns>An XDocument resulting from the request</returns>
        public XDocument Execute(string query)
        {
            HttpWebResponse response = null;

            if (query == null)
            {
                throw new ArgumentNullException("query");
            }

            var returnDoc = new XDocument();

            try
            {
                // Create and initialize the web request  
                var request = WebRequest.Create(Util.GetConnectionStringByName("VersionOneInstanceUrl") + "rest-1.v1/data/" + query) as HttpWebRequest;

                // Add authentication to request  
                if (request != null)
                {
                    request.PreAuthenticate = true; // this setting sends the credentials proactively, without being challenged by the server first. Much faster!
                    request.Credentials = new NetworkCredential(Util.GetConnectionStringByName("VersionOneUserId"), Util.GetConnectionStringByName("VersionOnePassword"));

                    request.UserAgent = "Agile Dashboard";

                    // TODO: As a performance improvement, we might be able to turn this on, and somehow persist the connection to Version One. SSL Connections are expensive to set up, so this would really help.
                    request.KeepAlive = false;

                    // Set timeout to a configured amount
                    request.Timeout = Properties.Settings.Default.RestRequestHttpTimeoutSeconds * 1000;

                    // Get response  
                    response = request.GetResponse() as HttpWebResponse;

                    if (request.HaveResponse && response != null)
                    {
                        // Get the response stream and load it into an xml doc
                        returnDoc = XDocument.Load(response.GetResponseStream());
                    }
                }
            }
            catch (WebException wex)
            {
                // This exception will be raised if the server didn't return 200 - OK  
                // Try to retrieve more information about the network error  
                if (wex.Response != null)
                {
                    using (var errorResponse = (HttpWebResponse)wex.Response)
                    {
                        if (Log.IsErrorEnabled)
                        {
                            Log.ErrorFormat(
                                "The server returned '{0}' with the status code {1} ({2:d}).",
                                errorResponse.StatusDescription,
                                errorResponse.StatusCode,
                                errorResponse.StatusCode);
                        }
                    }
                }
            }
            finally
            {
                if (response != null)
                {
                    response.Close();
                }
            }

            return returnDoc;
        }
    }
}